/* 
 * vm.c
 *  
 * Group: Fantastic Five
 * Date: 4/28/08 
 *
 * Description: Defines all functions implemented by VM
 */

#include "lexer.h"
#include "vm.h"
#include <stdio.h>

#define RC regs[8]
static struct regstr regs[9];

/* Runs error free program, stored in il */
void vm_run_program(FILE *out, FILE *in, FILE *err, struct instr_list *il)
{
    struct instr *temp = il->head;
    struct regstr temp_reg;

    /* main loop - loop until at end of instruction list
     * note: do not pop instructions, need to keep them due to jump statements */
    while(temp->next != NULL)
    {
        // ADD Reg,Reg
        if(temp->op == ADD && temp->type1 == REGISTER && temp->type2 == REGISTER)
        {
            ADD_Ra_Rb(temp->v1.r, temp->v2.r);
        }
        // ADD Reg,struct
        else if(temp->op == ADD)
        {
            temp_reg.v = temp->v2;
            temp_reg.reg_type = temp->type2;
            ADD_Ra_struct(temp->v1.r, temp_reg);
        }
        // SUB Reg,Reg
        else if(temp->op == SUB && temp->type1 == REGISTER && temp->type2 == REGISTER)
        {
            SUB_Ra_Rb(temp->v1.r, temp->v2.r);
        }
        // SUB Reg,struct
        else if(temp->op == SUB && temp->type1 == REGISTER)
        {
            temp_reg.v = temp->v2;
            temp_reg.reg_type = temp->type2;
            SUB_Ra_struct(temp->v1.r, temp_reg);
        }
        // SUB struct,Reg
        else if(temp->op == SUB)
        {
            temp_reg.v = temp->v1;
            temp_reg.reg_type = temp->type1;
            SUB_struct_Ra(temp_reg, temp->v2.r);
        }
        // MUL Reg,Reg
        else if(temp->op == MUL && temp->type1 == REGISTER && temp->type2 == REGISTER)
        {
            MUL_Ra_Rb(temp->v1.r, temp->v2.r);
        }
        // MUL Reg,struct
        else if(temp->op == MUL)
        {
            temp_reg.v = temp->v2;
            temp_reg.reg_type = temp->type2;
            MUL_Ra_struct(temp->v1.r, temp_reg);
        }
        // DIV Reg,Reg
        else if(temp->op == DIV && temp->type1 == REGISTER && temp->type2 == REGISTER)
        {
            DIV_Ra_Rb(temp->v1.r, temp->v2.r);
        }
        // DIV Reg,struct
        else if(temp->op == DIV && temp->type1 == REGISTER)
        {
            temp_reg.v = temp->v2;
            temp_reg.reg_type = temp->type2;
            DIV_Ra_struct(temp->v1.r, temp_reg);
        }
        // DIV struct,Reg
        else if(temp->op == DIV)
        {
            temp_reg.v = temp->v1;
            temp_reg.reg_type = temp->type1;
            DIV_struct_Ra(temp_reg, temp->v2.r);
        }
        // JZ Reg,line
        else if(temp->op == JZ)
        {
            temp = JZ_Ra_line(temp->v1.r, temp->v2.i, temp);
            continue;
        }
        // JNZ Reg,line
        else if(temp->op == JNZ)
        {
            temp = JNZ_Ra_line(temp->v1.r, temp->v2.i, temp);
            continue;
        }
        // JGT Reg,line
        else if(temp->op == JGT)
        {
            temp = JGT_Ra_line(temp->v1.r, temp->v2.i, temp);
            continue;
        }
        // JLT Reg,line
        else if(temp->op == JLT)
        {
            temp = JLT_Ra_line(temp->v1.r, temp->v2.i, temp);
            continue;
        }
        // JMP line
        else if(temp->op == JMP)
        {
            temp = JMP_line(temp->v1.i, temp);
            continue;
        }
        // CPY Reg,Reg
        else if(temp->op == CPY)
        {
            CPY_Ra_Rb(temp->v1.r, temp->v2.r);
        }
        // INC Reg
        else if(temp->op == INC)
        {
            INC_Ra(temp->v1.r);
        }
        // DEC Reg
        else if(temp->op == DEC)
        {
            DEC_Ra(temp->v1.r);
        }
        // GET Reg
        else if(temp->op == GET)
        {
            GET_Ra(temp->v1.r, in, out, err);
        }
        // PUT Reg
        else if(temp->op == PUT)
        {
            PUT_Ra(temp->v1.r);
        }
        // PTC char
        else if(temp->op == PTC)
        {
            PTC_char(temp->v1.c);
        }
        // CLR Reg
        else if(temp->op == CLR)
        {
            CLR_Ra(temp->v1.r);
        }
        // MOV Reg,struct
        else if(temp->op == MOV)
        {
            temp_reg.v = temp->v2;
            temp_reg.reg_type = temp->type2;
            MOV_Ra_struct(temp->v1.r, temp_reg);
        }
        // CMP Reg,Reg
        else if(temp->op == CMP)
        {
            CMP_Ra_Rb(temp->v1.r, temp->v2.r);
        }

        temp = temp->next;
    }
}

/* 
 * Implements the CPY Ra Rb instruction
 * Ra = source      Rb = destination
 */
void CPY_Ra_Rb(enum reg Ra, enum reg Rb)
{
    regs[Rb].reg_type = regs[Ra].reg_type;
    regs[Rb].v = regs[Ra].v;
}

/* 
 * Implements the CLR Ra instruction
 * Sets value in Ra equal to zero and changes type to INTEGER
 */
void CLR_Ra(enum reg Ra)
{
    regs[Ra].reg_type = INTEGER;
    regs[Ra].v.i = 0;
    regs[Ra].v.f = 0.0;
}

/* 
 * Implements the MOV Ra struct instruction 
 * Puts new_val into Ra
 */
void MOV_Ra_struct(enum reg Ra, struct regstr new_val)
{
    regs[Ra].reg_type = new_val.reg_type;
    regs[Ra].v = new_val.v;
}

/* 
 * Implements the CMP Ra Rb instruction
 * Stores result in comparison register, RC.v.i
 * 0 if equal, 1 if Ra > Rb, -1 if Ra < Rb
 */
void CMP_Ra_Rb(enum reg Ra, enum reg Rb)
{
    /* Set tolerances for comparison */
    float tol_high = 0.0001;
    float tol_low = -0.0001;

    if((regs[Ra].reg_type == INTEGER) && (regs[Rb].reg_type == INTEGER)) /* Both registers are ints, simple comparison */
    {
        if(regs[Ra].v.i == regs[Rb].v.i)
            RC.v.i = 0;
        else if(regs[Ra].v.i > regs[Rb].v.i)
            RC.v.i = 1;
        else
            RC.v.i = -1;
    }
    else if((regs[Ra].reg_type == FLOAT) && (regs[Rb].reg_type == FLOAT)) /* Both registers are floats */
    {
        if((((regs[Ra].v.f - regs[Rb].v.f) < tol_high)) && ((regs[Ra].v.f - regs[Rb].v.f) > tol_low))
            RC.v.i = 0;
        else if((regs[Ra].v.f - regs[Rb].v.f) > tol_high)
            RC.v.i = 1;
        else
            RC.v.i = -1;
    }
    else if(regs[Ra].reg_type == FLOAT) /* Ra is float, Rb is int */
    {
        if((((regs[Ra].v.f - regs[Rb].v.i) < tol_high)) && ((regs[Ra].v.f - regs[Rb].v.i) > tol_low))
            RC.v.i = 0;
        else if((regs[Ra].v.f - regs[Rb].v.i) > tol_high)
            RC.v.i = 1;
        else
            RC.v.i = -1;
    }
    else /* Ra is int, Rb is float */
    {
        if((((regs[Ra].v.i - regs[Rb].v.f) < tol_high)) && ((regs[Ra].v.i - regs[Rb].v.f) > tol_low))
            RC.v.i = 0;
        else if((regs[Ra].v.i - regs[Rb].v.f) > tol_high)
            RC.v.i = 1;
        else
            RC.v.i = -1;
    }
}

/* 
 * Implements the INC Ra instruction
 * Adds 1 to Ra, doesn't care if Ra is float or int
 */
void INC_Ra(enum reg Ra)
{
    if(regs[Ra].reg_type == FLOAT)
        regs[Ra].v.f += 1;
    else
        regs[Ra].v.i += 1;
}

/* 
 * Implements the DEC Ra instruction
 * Subtracts 1 from Ra, doesn't care if Ra is floar or int
 */
void DEC_Ra(enum reg Ra)
{
    if(regs[Ra].reg_type == FLOAT)
        regs[Ra].v.f -= 1;
    else
        regs[Ra].v.i -= 1;
}

/* 
 * Implements the PUT Ra instruction
 * Outputs the contents of Ra to stdout
 */
void PUT_Ra(enum reg Ra)
{
    if(regs[Ra].reg_type == INTEGER)
        fprintf(stdout, "%d", regs[Ra].v.i); /* print int */
    else
        fprintf(stdout, "%f", regs[Ra].v.f); /* print float */
}

/* 
 * Implements the PTC char instruction
 * Outputs the given character to stdout
 */
void PTC_char(char ch)
{
    fprintf(stdout, "%c", ch);
}

/*
 * ADD instruction for Register/Register parameters.
 * Adds two registers and places the result in the first register.
 */
void ADD_Ra_Rb(enum reg Ra, enum reg Rb)
{
    /* INTEGER and INTEGER */
    if ((regs[Ra].reg_type == INTEGER) && (regs[Rb].reg_type == INTEGER))
    {
        regs[Ra].v.i += regs[Rb].v.i;
    }
    /* FLOAT and FLOAT */
    else if ((regs[Ra].reg_type == FLOAT) && (regs[Rb].reg_type == FLOAT))
    {
        regs[Ra].v.f += regs[Rb].v.f;
    }
    /* FLOAT and INTEGER */
    else if ((regs[Ra].reg_type == FLOAT) && (regs[Rb].reg_type == INTEGER))
    {
        regs[Ra].v.f += (float)regs[Rb].v.i;
    }
    /* INTEGER and FLOAT */
    else
    {
        regs[Ra].v.f = (float)regs[Ra].v.i + regs[Rb].v.f;
        regs[Ra].reg_type = FLOAT;
    }
}

/*
 * ADD instruction for Register/Struct parameters.
 * Adds a register and a numerical value and places the result in the register.
 */
void ADD_Ra_struct(enum reg Ra, struct regstr newval)
{
    /* INTEGER and INTEGER */
    if ((regs[Ra].reg_type == INTEGER) && (newval.reg_type == INTEGER))
    {
        regs[Ra].v.i += newval.v.i;
    }
    /* FLOAT and FLOAT */
    else if ((regs[Ra].reg_type == FLOAT) && (newval.reg_type == FLOAT))
    {
        regs[Ra].v.f += newval.v.f;
    }
    /* FLOAT and INTEGER */
    else if ((regs[Ra].reg_type == FLOAT) && (newval.reg_type == INTEGER))
    {
        regs[Ra].v.f += (float)newval.v.i;
    }
    /* INTEGER and FLOAT */
    else
    {
        regs[Ra].v.f = (float)regs[Ra].v.i + newval.v.f;
        regs[Ra].reg_type = FLOAT;
    }
}

/*
 * SUB instruction for Register/Register inputs.
 * Subtracts two registers and places the result in the first register.
 */
void SUB_Ra_Rb(enum reg Ra, enum reg Rb)
{
    /* INTEGER and INTEGER */
    if ((regs[Ra].reg_type == INTEGER) && (regs[Rb].reg_type == INTEGER))
    {
        regs[Ra].v.i -= regs[Rb].v.i;
    }
    /* FLOAT and FLOAT */
    else if ((regs[Ra].reg_type == FLOAT) && (regs[Rb].reg_type == FLOAT))
    {
        regs[Ra].v.f -= regs[Rb].v.f;
    }
    /* FLOAT and INTEGER */
    else if ((regs[Ra].reg_type == FLOAT) && (regs[Rb].reg_type == INTEGER))
    {
        regs[Ra].v.f -= (float)regs[Rb].v.i;
    }
    /* INTEGER and FLOAT */
    else
    {
        regs[Ra].v.f = (float)regs[Ra].v.i - regs[Rb].v.f;
        regs[Ra].reg_type = FLOAT;
    }
}

/*
 * SUB instruction for Register/Struct parameters.
 * Subtracts a numerical value from a register and places the result in the register.
 */
void SUB_Ra_struct(enum reg Ra, struct regstr newval)
{
    /* INTEGER and INTEGER */
    if ((regs[Ra].reg_type == INTEGER) && (newval.reg_type == INTEGER))
    {
        regs[Ra].v.i -= newval.v.i;
    }
    /* FLOAT and FLOAT */
    else if ((regs[Ra].reg_type == FLOAT) && (newval.reg_type == FLOAT))
    {
        regs[Ra].v.f -= newval.v.f;
    }
    /* FLOAT and INTEGER */
    else if ((regs[Ra].reg_type == FLOAT) && (newval.reg_type == INTEGER))
    {
        regs[Ra].v.f -= (float)newval.v.i;
    }
    /* INTEGER and FLOAT */
    else
    {
        regs[Ra].v.f = (float)regs[Ra].v.i - newval.v.f;
        regs[Ra].reg_type = FLOAT;
    }
}

/*
 * SUB instruction for Struct/Register parameters.
 * Subtracts a register from a numerical value and places the result in the register.
 */
void SUB_struct_Ra(struct regstr newval, enum reg Ra)
{
    /* INTEGER and INTEGER */
    if ((regs[Ra].reg_type == INTEGER) && (newval.reg_type == INTEGER))
    {
        regs[Ra].v.i = newval.v.i - regs[Ra].v.i;
    }
    /* FLOAT and FLOAT */
    else if ((regs[Ra].reg_type == FLOAT) && (newval.reg_type == FLOAT))
    {
        regs[Ra].v.f = newval.v.f - regs[Ra].v.f;
    }
    /* FLOAT and INTEGER */
    else if ((regs[Ra].reg_type == FLOAT) && (newval.reg_type == INTEGER))
    {
        regs[Ra].v.f = (float)newval.v.i - regs[Ra].v.f;
    }
    /* INTEGER and FLOAT */
    else
    {
        regs[Ra].v.f = newval.v.f - (float)regs[Ra].v.i;
        regs[Ra].reg_type = FLOAT;
    }
}

/*
 * MUL instruction for two registers
 * Multiplies two registers and stores the value in the first
 */
void MUL_Ra_Rb(enum reg Ra, enum reg Rb)
{
    float temp;

    /* If Structure "borrowed" from CMP
     * Both registers are ints, integer result */
    if((regs[Ra].reg_type == INTEGER) && (regs[Rb].reg_type == INTEGER)) 
    {
        regs[Ra].v.i = regs[Ra].v.i * regs[Rb].v.i;
    }
    /* Both registers are floats */
    else if((regs[Ra].reg_type == FLOAT) && (regs[Rb].reg_type == FLOAT)) 
    {
        regs[Ra].v.f = regs[Ra].v.f * regs[Rb].v.f;
    }
    /* Ra is float, Rb is int */
    else if(regs[Ra].reg_type == FLOAT) 
    {
        regs[Ra].v.f = regs[Ra].v.f * (float) regs[Rb].v.i;
    }
    /* Ra is int, Rb is float */
    else 
    {   
        temp = (float) regs[Ra].v.i * regs[Rb].v.f;
        regs[Ra].v.f = temp;
        regs[Ra].reg_type = FLOAT;
    }
}

/*
 * MUL instruction for register and input value
 * Multiplies register and value and stores the value in the register
 */
void MUL_Ra_struct(enum reg Ra, struct regstr newval)
{
    float temp;
    
    /* If Structure "borrowed" from CMP
     * Both registers are ints, integer result */
    if((regs[Ra].reg_type == INTEGER) && (newval.reg_type == INTEGER)) 
    {
        regs[Ra].v.i = regs[Ra].v.i * newval.v.i;
    }
    /* Both registers are floats */
    else if((regs[Ra].reg_type == FLOAT) && (newval.reg_type == FLOAT)) 
    {
        regs[Ra].v.f = regs[Ra].v.f * newval.v.f;
    }
    /* Ra is float, Rb is int */
    else if(regs[Ra].reg_type == FLOAT) 
    {
        regs[Ra].v.f = regs[Ra].v.f * (float) newval.v.i;
    }
    /* Ra is int, Rb is float */
    else 
    {   
        temp = (float) regs[Ra].v.i * newval.v.f;
        regs[Ra].v.f = temp;
        regs[Ra].reg_type = FLOAT;
    }
}

/*
 * DIV instruction for two registers
 * Divides Ra/Rb and stores the value in the first
 */
void DIV_Ra_Rb(enum reg Ra, enum reg Rb)
{
    float temp;

    /* If Structure "borrowed" from CMP
     * Both registers are ints, integer result */
    if((regs[Ra].reg_type == INTEGER) && (regs[Rb].reg_type == INTEGER)) 
    {
        regs[Ra].v.i = regs[Ra].v.i / regs[Rb].v.i;
    }
    /* Both registers are floats */
    else if((regs[Ra].reg_type == FLOAT) && (regs[Rb].reg_type == FLOAT)) 
    {
        regs[Ra].v.f = regs[Ra].v.f / regs[Rb].v.f;
    }
    /* Ra is float, Rb is int */
    else if(regs[Ra].reg_type == FLOAT) 
    {
        regs[Ra].v.f = regs[Ra].v.f / (float) regs[Rb].v.i;
    }
    /* Ra is int, Rb is float */
    else 
    {   
        temp = (float) regs[Ra].v.i / regs[Rb].v.f;
        regs[Ra].v.f = temp;
        regs[Ra].reg_type = FLOAT;
    }
}

/*
 * DIV instruction for register and input value
 * Divides reg/struct and stores the value in the register
 */
void DIV_Ra_struct(enum reg Ra, struct regstr newval)
{
    float temp;

    /* If Structure "borrowed" from CMP
     * Both registers are ints, integer result */
    if((regs[Ra].reg_type == INTEGER) && (newval.reg_type == INTEGER)) 
    {
        regs[Ra].v.i = regs[Ra].v.i / newval.v.i;
    }
    /* Both registers are floats */
    else if((regs[Ra].reg_type == FLOAT) && (newval.reg_type == FLOAT)) 
    {
        regs[Ra].v.f = regs[Ra].v.f / newval.v.f;
    }
    /* Ra is float, Rb is int */
    else if(regs[Ra].reg_type == FLOAT) 
    {
        regs[Ra].v.f = regs[Ra].v.f / (float) newval.v.i;
    }
    /* Ra is int, Rb is float */
    else 
    {   
        temp = (float) regs[Ra].v.i / newval.v.f;
        regs[Ra].v.f = temp;
        regs[Ra].reg_type = FLOAT;
    }
}

/*
 * DIV instruction for register and input value
 * Divides struct/reg and stores the value in the register
 */
void DIV_struct_Ra(struct regstr newval, enum reg Ra)
{
    float temp;

    /* If Structure "borrowed" from CMP
     * Both registers are ints, integer result */
    if((regs[Ra].reg_type == INTEGER) && (newval.reg_type == INTEGER)) 
    {
        regs[Ra].v.i = newval.v.i / regs[Ra].v.i;
    }
    /* Both registers are floats */
    else if((regs[Ra].reg_type == FLOAT) && (newval.reg_type == FLOAT)) 
    {
        regs[Ra].v.f = newval.v.f / regs[Ra].v.f;
    }
    /* Ra is float, Rb is int */
    else if(regs[Ra].reg_type == FLOAT) 
    {
        regs[Ra].v.f = (float) newval.v.i / regs[Ra].v.f;
    }
    /* Ra is int, Rb is float */
    else 
    {   
        temp = newval.v.f / (float) regs[Ra].v.i;
        regs[Ra].v.f = temp;
        regs[Ra].reg_type = FLOAT;
    }
}

/*
 * JZ instruction.
 * Jumps to the specified line number if register = 0.  Returns a pointer.
 * Otherwise, just advance to the next line.
 */
struct instr *JZ_Ra_line(enum reg Ra, int linenum, struct instr *curline)
{
    float value;

    if (regs[Ra].reg_type == INTEGER)
        value = (float)regs[Ra].v.i;
    else if (regs[Ra].reg_type == FLOAT)
        value = regs[Ra].v.f;

    if ((value - 0.0001) < 0)   // Jump to linenum.
    {
        while (linenum > curline->linenum)  // Go forward to desired line.
        {
            if (curline->next != NULL)
                curline = curline->next;
            else
                break;  // linenum is beyond the program, prevent infinite loop
        }
        while (linenum < curline->linenum)  // Go backward to desired line.
        {
            if (curline->prev != NULL)
                curline = curline->prev;
            else
                break;  // linenum is beyond the program, prevent infinite loop
        }
    }
    else    // Do not jump to linenum.  Just advance to next line.
    {
        curline = curline->next;
    }

    return curline;
}

/*
 * JNZ instruction.
 * Jumps to the specified line number if register != 0.  Returns a pointer.
 * Otherwise, just advance to the next line.
 */
struct instr *JNZ_Ra_line(enum reg Ra, int linenum, struct instr *curline)
{
    float value;

    if (regs[Ra].reg_type == INTEGER)
        value = (float)regs[Ra].v.i;
    else if (regs[Ra].reg_type == FLOAT)
        value = regs[Ra].v.f;

    if ((value - 0.0001) > 0)   // Jump to linenum.
    {
        while (linenum > curline->linenum)  // Go forward to desired line.
        {
            if (curline->next != NULL)
                curline = curline->next;
            else
                break;  // linenum is beyond the program, prevent infinite loop
        }
        while (linenum < curline->linenum)  // Go backward to desired line.
        {
            if (curline->prev != NULL)
                curline = curline->prev;
            else
                break;  // linenum is beyond the program, prevent infinite loop
        }
    }
    else    // Do not jump to linenum.
    {
        curline = curline->next;
    }

    return curline;
}

/*
 * JMP instruction.
 * Jumps to the specified line number, if possible.  Returns a pointer.
 * Otherwise, the line number to jump to is out of range.  Program ends.
 */
struct instr *JMP_line(int linenum, struct instr *curline)
{
    while (linenum > curline->linenum)  // Go forward to desired line.
    {
        if (curline->next != NULL)
            curline = curline->next;
        else
            break;  // linenum is beyond the program, prevent infinite loop
    }
    while (linenum < curline->linenum)  // Go backward to desired line.
    {
        if (curline->prev != NULL)
            curline = curline->prev;
        else
            break;  // linenum is beyond the program, prevent infinite loop
    }

    return curline;
}

/*
 * Returns a pointer to the node in instruction list that should be the next implimented line.
 * If the register is greater than zero, it jumps to the given line.  Otherwise, it jumps to the next line.
 * If it does not jump, it returns the next line.  If it does jump, it returns the line you jumped to.
 * If the line to jump to is passed the end of the list, then it returns the last line of the program.
 * Specifically then, if your VM code moves to the next line at the end of every itteration, you 
 * will need to be sure to take into account that these jump functions do that already. 
 * If you can think of a better way to do a jump by all means change it.
 */
struct instr * JGT_Ra_line(enum reg Ra, int linenum, struct instr * curline)
{
    float value;

    if (regs[Ra].reg_type == INTEGER)
        value = (float)regs[Ra].v.i;
    else if (regs[Ra].reg_type == FLOAT)
        value = regs[Ra].v.f;

    if (value > 0.0)    // Jump to linenum.
    {
        while (linenum > curline->linenum)  // Go forward to desired line.
        {
            if (curline->next != NULL)
                curline = curline->next;
            else
                break;  // linenum is beyond the program, prevent infinite loop
        }
        while (linenum < curline->linenum)  // Go backward to desired line.
        {
            if (curline->prev != NULL)
                curline = curline->prev;
            else
                break;  // linenum is beyond the program, prevent infinite loop
        }
    }
    else
    {
        curline = curline->next;    // Do not make the jump.  Advance to next line.
    }

    return curline; // Return the line we have jumped to.
}

/*
 * Returns a pointer to the node in the instruction list, if the register is less than zero, that is the next
 * line that needs to be implemented.
 */
struct instr * JLT_Ra_line(enum reg Ra, int linenum, struct instr * curline)
{
    float value;    // The register's value, that we're checking against 0, is assigned to this.

    if (regs[Ra].reg_type == INTEGER)
        value = (float)regs[Ra].v.i;
    else if (regs[Ra].reg_type = FLOAT)
        value = regs[Ra].v.f;

    if (value < 0.0)    // Make the jump
    {
        while (linenum > curline->linenum)  // Go forward to desired line.
        {
            if (curline->next != NULL)
                curline = curline->next;
            else
                break;  // linenum is beyond the program, prevent infinite loop
        }
        while (linenum < curline->linenum)  // Go backward to desired line.
        {
            if (curline->prev != NULL)
                curline = curline->prev;
            else
                break;  // linenum is beyond the program, prevent infinite loop
        }
    }
    else
    {
        curline = curline->next;    // Do not make the jump.  Advance to next line.
    }

    return curline; // Return the line we have jumped to.
}

/*
 * GET instruction.
 * Prompts the User for input.  They must enter a number or it will blow up.
*/
void GET_Ra(enum reg Ra, FILE *in, FILE *out, FILE *err)
{
    float entry_f;
    int entry_i;
    char type[2] = "x";

    CLR_Ra(Ra); // Clear that shit out

    fprintf(out, "Do you want to enter a float or an int? Type f or i: ");  // Get type of number they want to enter

    while(type[0] != 'f' && type[0] != 'F' && type[0] != 'i' && type[0] != 'I')
    {
        fscanf(in, "%1s%*[^\n]%*c", type);
        fprintf(out, "\n");
            
        /* user wants to enter a float */
        if(type[0] == 'f' || type[0] == 'F')
        {
            fprintf(out, "Enter a number: ");
            fscanf(in, "%f", &entry_f);

            regs[Ra].reg_type = FLOAT;
            regs[Ra].v.f = entry_f;
        }
        /* user wants to enter an int */
        else if(type[0] == 'i' || type[0] == 'I')
        {
            fprintf(out, "Enter a number: ");
            fscanf(in, "%i", &entry_i);

            regs[Ra].reg_type = INTEGER;
            regs[Ra].v.i = entry_i;
        }
        /* user is an idiot and can't figure out how to type the correct letter */
        else
            fprintf(err, "Invalid entry, try again: ");
    } 
}
